//1.promise 接收一个函数，且立即执行
//2.内部传如resolve，reject方法
//3.3个状态，一旦改变，便不再改变
//4.then方法返回一个新的promise对象,
//5.异步时，then方法里可能还没完成，由于then方法可以链式调用，其传入的回调函数需要用数组保存下来。
//6.then方法不传函数时，需要将默认的函数传入下一个then方法。
class MyPromise {
  PENDING = 'pending';
  FULFILLED = 'fulfilled';
  REJECTED = 'rejected';
  status = PENDING;
  //then添加的回调方法存储位置
  onfilledCallback = [];
  onrejectedCallback = [];
  //存储成功或失败接收的参数
  value = undefined;
  reason = undefined;

  constructor(fn) {
    try {
      fn(this.resolve, this.reject);
    } catch (e) {
      this.reject('err');
    }
  }

  resolve = value => {
    //状态一旦改变便不再变。
    if (this.status !== PENDING) return;
    state = FULFILLED;
    //遍历执行then方法添加的回调
    while (this.onfilledCallback.length) this.onfilledCallback.unshift()();
    this.value = value;
  };
  reject = reason => {
    if (this.status !== PENDING) return;
    state = REJECTED;
    while (this.onfilledCallback.length) this.onfilledCallback.unshift()();
    this.reason = reason;
  };
  then(fulfiledcallback, rejectcallback) {
    //then方法不传，需将参数默认沿着链条传下去
    fulfiledcallback = fulfiledcallback ? fulfiledcallback : val => val;
    rejectcallback = rejectcallback
      ? rejectcallback
      : reason => {
          throw reason;
        };
    //then方法需要返回一个新的promise对象
    let promise = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        //settimeout为了异步获取 变量promise
        setTimeout(() => {
          try {
            //对状态成功的代码里进行异常捕获
            let x = fulfiledcallback(this.value);
            resolvePromise(promise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = rejectcallback(this.reson);
            resolvePromise(promise, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      } else {
        //这里往成功回调数组里push处理好以后的函数
        this.onfilledCallback.push(() => {
          setTimeout(() => {
            try {
              let x = fulfiledcallback(this.value);
              resolvePromise(promise, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
        this.onrejectedCallback.push(() => {
          setTimeout(() => {
            try {
              let x = rejectcallback(this.reson);
              resolvePromise(promise, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });
    return promise;
  }
  catch(failcallback) {
    this.then(undefined, failcallback);
  }
  //1.返回新的promise对象2.无论成功，失败都执行
  finally(callback) {
    return this.then(
      value => { //处理finally返回promise任务时，后面的链条需要等待
      return  MyPromise.resolve(callback()).then(()=>value)
      },
      reason =>{
        return MyPromise.resolve(callback()).then(()=>{throw reason})
      } 
    );
  }
  static all(arrary) {
    let arr = []; //保存执行的结果
    let index = 0;
    //首先all方法会返回一个新的promise对象
    return new MyPromise((resolve, reject) => {
      function add(key, val) {
        arr[key] = val;
        index++;
        if (index === arrary.length) {
          //说明所有的结果已完成
          resolve(arr);
        }
      }
      for (let i = 0; i < arrary.length; i++) {
        let cur = arrary[i];
        if (cur instanceof MyPromise) {
          cur.then(
            val => add(i, val),
            reason => reject(reason) //有一个错误则整个出错
          );
        } else {
          add(i, cur);
        }
      }
    });
  }
  static resolve(x) {
    if (x instanceof MyPromise) return x; //是promise对象，直接返回，不是则包装成promise对象返回
    return new MyPromise((resove, reject) => {
      resove(x);
    });
  }
}

//判断x 是不是promise自身
//判断x 如果是值，直接返回，如果是promise，查看返回结果，再确定成功或失败
function resolvePromise(promise, x, resolve, reject) {
  if (promise === x) {
    return reject(new TypeError('can not return promise itself'));
  }
  if (x instanceof MyPromise) {
    //promise对象
    x.then(resolve, reject);
  } else {
    //普通值
    resolve(x);
  }
}
